//
//  Ant.cpp
//  AntSimulation
//


#include "Ant.h"
#include <string>
#include "Creator.h"//for creating foodhills

Ant::Ant() {
	std::cout<<" ant created, ";
	this->hasFood=false;
	this->alreadyActed=false;
	this->livecount=300;
	this->distance2food=-1;
	this->visitedAreasCleaned=true;
	this->diffXmoved=this->diffYmoved=0;
}
										   
Ant::~Ant(void) {
	//std::cout<<"destroy ant "<<this->getNumber()<<std::endl;
}

void Ant::act(void) 
{
	std::cout<<std::endl<<"ant "<<this->getNumber()<<" acting";
	if(this->alreadyActed==true)
	{
		//std::cout<<"Ant "<<this->getNumber()<<" has already acted in this turn"<<std::endl;
		this->alreadyActed=false;
		return;
	}

	if(this->get_livecount()<=0)
	{
		// if the dying ant has food, check the list of the area for a foodhill and add 1 food
		// or create a new foodhill with 1 food
		if(this->hasFood==true)//if the dying ant has some food..
		{
			bool foodreleased=false;
			for(std::list<Item*>::iterator foodfind = this->getCurrArea()->items.begin();foodfind!=(this->getCurrArea()->items.end());++foodfind)
			{
				if(typeid(*(*foodfind)).name()==typeid(Food).name())
				{
					//cast the item to foodhill
					Food* thisfood = dynamic_cast<Food*>(*foodfind);
					thisfood->set_amount(thisfood->get_amount()+1);
					foodreleased=true;
				}

			}
			if(foodreleased==false)//no anthill on the area, create a new one
			{
				Food* newfoodhill = Creator::getInstance()->Create_Food(1);
				this->getCurrArea()->AddToListFront(newfoodhill);
			}
		}
		//remove the ant from the list of the last area
		(getCurrArea()->itemiterator)=getCurrArea()->items.erase(getCurrArea()->itemiterator);
		
		delete this;//delete the ant
		return;
	}


	//Is there food or an anthill at the current area?
	for(std::list<Item*>::iterator find = this->getCurrArea()->items.begin();find!=(this->getCurrArea()->items.end());++find)
	{
		if(typeid(*(*(find))).name()==typeid(Food).name())
		{
			//reduce the amount of food on the area, but only if the ant is able to carry food (this->hasfood==false)
			if(this->hasFood==false)
			{
				Food* thisfood = dynamic_cast<Food*>(*find);//Cast the item to food, to get access to the amount...

				if(thisfood->get_amount()>0)//if the foodamount=0, the fooditem should be removed, perhaps by the actall() method??
				{
					thisfood->set_amount(thisfood->get_amount()-1);
					this->hasFood=true;
				}						  
				else{
					//TODO: remove the foodhill from the list
				}

				this->distance2food=0;
			}
		}

		if(typeid(*(*find)).name()==typeid(Anthill).name())
		{
			//release the food carried by the ant, and save it to the anthill
			if(this->hasFood==true)
			{			
				std::cout<<std::endl<<"ant "<<this->getNumber()<<" reached anthill and places food"<<std::endl;
				//increase the pheromonelevel, but only by 1
				if(this->getCurrArea()->get_pheromonelevel()<10){
					this->getCurrArea()->set_pheromonelevel(this->getCurrArea()->get_pheromonelevel()+1);
				}

				//cast item to anthill, place food
				Anthill* thishill = dynamic_cast<Anthill*>(*find);
				std::cout<<"thishill-current foodcount: "<<thishill->get_foodcount();
				thishill->set_foodcount(thishill->get_foodcount()+1);
				std::cout<<"thishill-new foodcount: "<<thishill->get_foodcount();
				//getchar();

				this->distance2food=-1;

				//increase the livecounter of the ant
				this->set_livecount(200);

				//reset the position differences
				//this->diffXmoved=this->diffYmoved=0;
				this->hasFood=false;
				this->visitedAreasCleaned=false;
			}
		}
	}



	if(this->hasFood==true)//Go back to the anthill
	{
		std::cout<<" hasfood=true"<<std::endl;
		//std::cout<<"Ant "<<this->getNumber()<<"on Area "<<this->getCurrArea()->getNumber()<<" moving home, x="<<this->diffXmoved<<" y="<<this->diffYmoved<<std::endl;
		//getchar();
		//increase the pheromonlevel of the current area, if the ant has food
		this->distance2food++;
		
		if(this->distance2food<5){
			if(this->getCurrArea()->get_pheromonelevel()<10){
				this->getCurrArea()->set_pheromonelevel(this->getCurrArea()->get_pheromonelevel()+(10-(this->distance2food)));//increase by 2
			}
		}else{
			if(this->getCurrArea()->get_pheromonelevel()<10){
				this->getCurrArea()->set_pheromonelevel(this->getCurrArea()->get_pheromonelevel()+1);//increase by 1
			}
		}

		//std::cout<<"Ant "<<this->getNumber()<<" going home, current Area: "<<this->getCurrArea()->getNumber()<<" visited areas:"<<std::endl;
		
		//for(std::list<Area*>::iterator areas = this->visitedAreas.begin();areas!=(this->visitedAreas.end());++areas)
		//{
		//	//std::cout<<std::endl<<"\tArea Nmb. "<<(*areas)->getNumber();
		//}
		//		  

		//Search and delete redundant areas....
		//std::cout<<std::endl<<"deleting redundant areas..."<<std::endl;
		if(this->visitedAreasCleaned==false && !(this->visitedAreas.empty()))	 
		{
			std::cout<<std::endl<<"   cleaning list....";
			for(std::list<Area*>::iterator it1 = this->visitedAreas.begin();it1!=(this->visitedAreas.end());++it1)
			{
			   for(std::list<Area*>::iterator it2 = this->visitedAreas.begin(); it2!=this->visitedAreas.end();++it2)
			   {
				   if(it2==it1)
				   {
					   ++it2;
					   if(it2==this->visitedAreas.end()){
						   break;
					   }
				   }
			   
				   if(it2!=this->visitedAreas.end() && it1!=this->visitedAreas.end()){
					   //compare the searchIt Iterator and the deleteIt-Iterator
					   if((*it1)->getNumber()==(*it2)->getNumber())
					   {
						   //delete range of redundant areas
						   //std::list erase includes the element pointed by it1, but not the element pointed by it2
						   this->visitedAreas.erase(it1,it2);
						   it1=it2;
					   }
				   }
			   }
			}

			std::cout<<std::endl<<"Cleaned list:";
			for(std::list<Area*>::iterator areas = this->visitedAreas.begin();areas!=(this->visitedAreas.end());++areas)
			{
				std::cout<<std::endl<<"\tArea Nmb. "<<(*areas)->getNumber();
			}
			this->visitedAreasCleaned=true;
		}
		//getchar();


		//The visitedAreas-list is clean, set nextArea to the first in the list
		this->setNextArea(this->visitedAreas.front());
		std::cout<<std::endl<<"next area set...";
		
			
	}
	else{//the ant doesn't have food...

		//calculate the next area
		this->setNextArea(calcNextArea(this->getCurrArea()));

		//if the new area index is lower than the current one, its sure, that the ant will not act again in this round
		//so when the new index is lower, dont set the alreadyAct value to true, otherwise the ant will also not act in
		//the next round...
		if(this->getNextArea()!=NULL){
			if(this->getNextArea()->getNumber()>=this->getCurrArea()->getNumber()){
				this->alreadyActed=true;
			}
		}

		//if the target-area is outside the environment (NULL), stay at the current area for the rest of the round and reconsider...
		if(this->getNextArea()==NULL){this->setNextArea(this->getCurrArea());}

		//Put the pointer to the current Area in the visitedAreas-list
		if(this->getNextArea()!=NULL)
		{
			this->visitedAreas.push_front(this->getCurrArea());
			this->visitedAreasCleaned=false;
		}
		
	}


	//according to the pointer to the next Area
	//delete the ant from the list of the current area and put in into the
	//list of the next area;
	std::cout<<std::endl<<"ant "<<this->getNumber()<<" moving from area "<<this->getCurrArea()->getNumber()<<" to Area "<<this->getNextArea()->getNumber();
	if(this->getNextArea()!=NULL && this->getCurrArea()!=this->getNextArea()){
		this->getNextArea()->AddToListFront(this); //Put the (pointer to the) ant to the list of the next Area...
		
		//remove the ant from the list of the last area
		(getCurrArea()->itemiterator)=getCurrArea()->items.erase(getCurrArea()->itemiterator);// the iterator automatically points to the next element in the list
	
		this->setLastArea(this->getCurrArea());//The old "CurrArea"...
		this->setCurrArea(this->getNextArea());//Set the new current area to the current area of the ant

		if((!(this->visitedAreas.empty())) && this->hasFood==true)
		{
			//Pop the area off the visitedAreas-list
			this->visitedAreas.pop_front();
			std::cout<<std::endl<<"popped..."<<std::endl;
			for(std::list<Area*>::iterator areas = this->visitedAreas.begin();areas!=(this->visitedAreas.end());++areas)
			{
				std::cout<<std::endl<<"\tArea Nmb. "<<(*areas)->getNumber();
			}
		}
	}

	//decrease the livecount:
	this->decrease_livecount();

}

void Ant::set_hasFood(bool _value)
{
	this->hasFood=_value;
}


bool Ant::get_hasFood(void)
{	
	return this->hasFood;
}


void Ant::set_livecount(unsigned int _livecount)//sets the livecount of the ant, max=200
{
	if(_livecount <= 200)
	{
		this->livecount=_livecount;
	}
}

unsigned Ant::get_livecount(void)
{
	return this->livecount;
}

void Ant::decrease_livecount(void)//livecount -1
{
	if(this->livecount >0)
	{
		this->livecount--;
	}
}


void Ant::increase_livecount(void)//livecount +1
{
	if(this->livecount <200)
	{
		this->livecount++;
	}
}

void Ant::setCurrArea(Area* _curr_area)
{
	this->curr_area=_curr_area;
}

Area* Ant::getCurrArea(void)
{
	return this->curr_area;
}

void Ant::setNextArea(Area* _next_area)
{
	this->next_area=_next_area;
}

Area* Ant::getNextArea(void)
{
	return this->next_area;
}

void Ant::setLastArea(Area* _last_area)
{
	this->last_area=_last_area;
}

Area* Ant::getLastArea(void)
{
	return this->last_area;
}

Area* Ant::calcNextArea(Area* _currArea)//finds the area, where the ant will move on its next turn
{
	//Create a random number between 1 and 10 for each surrounding area (north, east, south and west)
	unsigned int north, east, south, west;
	
	north=1+rand()%10;
	east=1+rand()%10;
	south=1+rand()%10;
	west=1+rand()%10;


	//The last area should get a low number, because the ant should not go back
	if(this->getLastArea()!=NULL){
		if(_currArea->get_north()==this->getLastArea()){
			north=1;
		}
		else if(_currArea->get_east()==this->getLastArea()){
			east=1;
		}
		else if(_currArea->get_south()==this->getLastArea()){
			south=1;
		}
		else if(_currArea->get_west()==this->getLastArea()){
			west=1;
		}
	}
	
	//get the pheromone-level of the surrounding areas
	//catch the pheromone-index and create the product of the random number and the pheromone-level
	if(this->curr_area->get_north()!=NULL){
		north=north*(this->curr_area->get_north()->get_pheromonelevel());
	}
	else{
		north=0;}

	if(this->curr_area->get_east()!=NULL){
		east=east*(this->curr_area->get_east()->get_pheromonelevel());
	}
	else{
		east=0;
	}

	if(this->curr_area->get_south()!=NULL){
		south=south*(this->curr_area->get_south()->get_pheromonelevel());
	}
	else{
		south=0;
	}


	if(this->curr_area->get_west()!=NULL){
		west=west*(this->curr_area->get_west()->get_pheromonelevel());
	}
	else{
		west=0;
	}

	
	//according to the product of the random number and the pheromone-index
	//the ant decides which way to go...
	unsigned max_value=get_max(get_max(north,east),get_max(south,west));
	
	if(max_value==north){;return this->curr_area->get_north();}
	else if(max_value==east){;return this->curr_area->get_east();}
	else if(max_value==south){;return this->curr_area->get_south();}
	else{;return this->curr_area->get_west();}


}

unsigned int Ant::get_max(unsigned int a, unsigned int b)//returns the max of two values
{
	return ((a>b)?a:b);
}







